require 'gameobject'
require 'gosu'
require 'bullet'
require 'explosion'
include Gosu
include Globals

class Player < GameObject
  MAX_SPEED = 8
  PROTECTION_SPAN = 200
 attr_accessor :x, :y, :vel_x, :vel_y, :current_speed, :angle
 attr_accessor :lives, :score, :wins, :deaths
 attr_reader :is_dead, :id, :name, :color
 attr_accessor :controls_index

  def initialize(game, screen, color)
    super(screen)
    case color
    when :blue
      @bullet_image = game.load_tiles("bullet_blue.png", 10, 40)
      @explode_sound = game.sounds["ship_explode1_remix.ogg"]
      @shoot_sound = game.sounds["player_shoot1_remix.ogg"]
      @defeat_sound = game.sounds["defeat_blue_remix.ogg"]
      @bullet_color = "blue_bullet"
      @color = Color.new(0xff6666ff)
      @name = "Blue"
      @controls_index = 0 # index to use when identifying controls in GameScreen
#-------------------------------------------------------------------------
    when :red
      @bullet_image = game.load_tiles("bullet_red.png", 10, 40)
      @explode_sound = game.sounds["ship_explode2_remix.ogg"]
      @shoot_sound = game.sounds["player_shoot2_remix.ogg"]
      @defeat_sound = game.sounds["defeat_red_remix.ogg"]
      @bullet_color = "red_bullet"
      @color = Color.new(0xffff6666)
      @name = "Red"
      @controls_index = 1 
    when :green      
      @bullet_image = game.load_tiles("bullet_green.png", 10, 40)
      @explode_sound = game.sounds["ship_explode3_remix.ogg"]
      @shoot_sound = game.sounds["player_shoot3_remix.ogg"]
      @defeat_sound = game.sounds["defeat_green_remix.ogg"]
      @bullet_color = "green_bullet"
      @color = Color.new(0xff66ff66)
      @name = "Green"
      @controls_index = 2 
#---------------------------------------------------------------------------
    when :purple
      @bullet_image = game.load_tiles("bullet_purple.png", 10, 40)
      @explode_sound = game.sounds["ship_explode4_remix.ogg"]
      @shoot_sound = game.sounds["player_shoot4_remix.ogg"]
      @defeat_sound = game.sounds["defeat_purple_remix.ogg"]
      @bullet_color = "purple_bullet"
      @color = Color.new(0xffff44ff)
      @name = "Purple"
      @controls_index = 3
    end
    @image = game.images["../3d_renders/space_ship.png"]
    @e_img = game.images["explosion.png"]
    @image_thrst = game.images["../3d_renders/thrusters.png"]
    @image_rev = game.images["../3d_renders/reversers.png"]
    @thrust_color = Color.new(0xffffffff)
    @particle_image = game.images["../3d_renders/particle.png"]
    @warp_sound = game.sounds["warp_remix.ogg"]
    @re_deploy_sound = game.sounds["re_deploy.ogg"]
    @force_field = game.load_tiles("force_field.png", 80, 80)
    @field_color = Color.new(0xffffffff)

    @game = game
    @screen = screen
    @ship_color = color
    @turn_speed = 3
    @id = @ship_color
    @invincible = false # invincibility powerup
    @protected = false # respawn protection
    @thrust_mode = :none
    @x = @y = 0
    @z = PLAYER_Z
    @vel_x = @vel_y = @angle = 0
    @is_dead = false
    @current_speed = @score = @life_span = @wins = @deaths = 0
    #@powerup_counters = {"speed" => 0, "slow" => 0, "turn" => 0,
    #                    "turn_slow" => 0, "invincibility" => 0}
    @powerup_counters = {}
    @lives = 10
    @charge = 20
    @max_speed = MAX_SPEED
    @acceleration = 0.15
  end

  def warp_to(x, y, make_noise = true)
    @x, @y = x, y
    if make_noise and @screen.game_options["sound"]
      @warp_sound.play.volume = @screen.game_options["sound_volume"] 
    end
  end

  def shoot
    unless @charge < 20 or @is_dead
      Bullet.new(@screen, @game, @bullet_image, @x, @y, @angle, @bullet_color)
      if @screen.game_options["sound"]
        @shoot_sound.play.volume = @screen.game_options["sound_volume"] 
      end
      @charge -= 20
    end
  end

  def turn_left
    return if @is_dead
    @angle -= @turn_speed
  end

  def turn_right
    return if @is_dead
    @angle += @turn_speed
  end

  def accelerate
    return if @is_dead
    @vel_x += offset_x(@angle, @acceleration)
    @vel_y += offset_y(@angle, @acceleration)
    @current_speed = distance(0, 0, @vel_x, @vel_y)
    if @current_speed > @max_speed
      speed_angle = Gosu::angle(0, -@vel_y, @vel_x, 0)
      @vel_x = offset_x(speed_angle, @max_speed)
      @vel_y = offset_y(speed_angle, @max_speed)
    end
    @thrust_mode = :forward
  end

  def reverse
    @vel_x -= offset_x(@angle, @acceleration)
    @vel_y -= offset_y(@angle, @acceleration)
    @current_speed = distance(0, 0, @vel_x, @vel_y)
    if @current_speed > @max_speed
      speed_angle = Gosu::angle(0, -@vel_y, @vel_x, 0)
      @vel_x = offset_x(speed_angle, @max_speed)
      @vel_y = offset_y(speed_angle, @max_speed)
    end
    @thrust_mode = :reverse
  end

  def update
    @x += @vel_x
    @y += @vel_y
    @x %= (WIDTH + 60)
    @y %= (HEIGHT + 60)
    @charge += 1 unless @charge >= 20
    @life_span += 1
    @thrust_color.alpha = (@life_span*4) % 64 + 190
    @thrust_color.alpha = (50 * Math.sin((3.14159*@life_span)/5)).to_i + 205

    # run through the powerups
    @max_speed = MAX_SPEED
    @acceleration = 0.15
    @turn_speed = 3
    @invincible = false
    @thrust_color.blue = @thrust_color.green = 255
    @color.alpha = 255
    @powerup_counters.delete_if {|p_up, val| val -=1; @powerup_counters[p_up] = val; val == 0}
    @powerup_counters.each do |p_up, val|
      case p_up
      when "speed"
        @max_speed = MAX_SPEED + 4
        @acceleration = 0.3
        @thrust_color.blue = 0
      when "slow"
        @max_speed = MAX_SPEED - 4
        @acceleration = 0.07
        @thrust_color.blue = @thrust_color.green = 100
      when "turn"
        @turn_speed = 6
      when "turn_slow"
        @turn_speed = 1.5
      when "invincibility"
        @invincible = true
        @color.alpha = 100
      end
    end

    #@vel_x *= 0.9985
    #@vel_y *= 0.9985
    true
  end

  def draw
    return if @is_dead
    @image.draw_rot(@x, @y, @z, @angle, 0.5, 0.5, 1, 1, @color)
    if @thrust_mode == :forward
      @image_thrst.draw_rot(@x, @y, @z, @angle, 0.5,0.5,1,1, @thrust_color)
      # draw the thruster flames
    end
    if @thrust_mode == :reverse
      @image_rev.draw_rot(@x, @y, @z, @angle, 0.5, 0.5, 1, 1, @thrust_color) 
      # draw the reverser flames
    end
    if @protected
      i = (@life_span/3) % @force_field.size
      #image index
      @field_color.alpha = (255 - 255 * @life_span.to_f/PROTECTION_SPAN.to_f).to_i
      @force_field[i].draw_rot(@x, @y, @z, 0, 0.5, 0.5, 1, 1, @field_color)
    end

    @thrust_mode = :none 
    # reset the thrust mode each loop
  end

  def die(death_cause = :normal)
    # such a mess. I may get around to improving this method
    return if @is_dead
    @lives -= 1 unless @lives == :infinite
    Explosion.new(@screen, @game, @particle_image, @e_img, @x, @y, @z, :normal)
    @is_dead = true
    @current_speed = 0
    case @screen.game_options["mode"]
    when :slaughter
      reset
    when :slap_jack
      @score -= 1 if death_cause == :opponent
      if @score != 0 then reset else @lives = 0 end
    else
      @score -= 1 
      reset if @lives != 0
    end
    @deaths += 1
    if @screen.game_options["sound"]
      @explode_sound.play.volume =  @screen.game_options["sound_volume"]
      if @lives == 0 and @screen.players.size != 1
        @defeat_sound.play.volume = @screen.game_options["sound_volume"] unless @screen.game_options["mode"] == :star_fleet
      end
    end
  end

  def reset # reset after dying
    Task.new(@screen, @game, :wait => 120) do
      if @life_span < PROTECTION_SPAN
        re_deploy
      else
        normalize
        warp_to rand(WIDTH - 200) + 100, rand(HEIGHT - 200) + 100
        @life_span = @vel_x = @vel_y = @angle = 0
        @protected = true
        @field_color.alpha = 255
        Task.new(@screen, @game, :wait => PROTECTION_SPAN) { @protected = false }
      end
    end
  end

  def re_deploy
    normalize
    warp_to rand(WIDTH), rand(HEIGHT)
    @life_span = 0
    @vel_x = @vel_y = @angle = 0
    unless @lives == :infinite
      @lives += 1
      if @screen.game_options["sound"]
        @re_deploy_sound.play.volume = @screen.game_options["sound_volume"]
      end
    end
  end

  def obj_id
    return false if @lives == 0
    @id
  end

  def check(x, y, radius, cause = :normal)
    if distance(@x, @y, x, y) < radius and !invincible?
      die(cause)
      true
    else
      false
    end
  end

  def check_powerup(x, y, radius)
    return false if @is_dead
    distance(@x, @y, x, y) < radius
  end

  def powerup(type)
    case type
    when :speed
      @powerup_counters["speed"] = 1000
      @powerup_counters.delete("slow")
    when :slow
      @powerup_counters["slow"] = 1000
      @powerup_counters.delete("speed")
    when :turn
      @powerup_counters["turn"] = 1000
      @powerup_counters.delete("turn_slow")
    when :turn_slow
      @powerup_counters["turn_slow"] = 1000
      @powerup_counters.delete("turn")
    when :invincibility
      @powerup_counters["invincibility"] = 1000
=begin
    # deprecated style of doing powerups
    when :speed
      #@max_speed = MAX_SPEED + 4
      #@acceleration = 0.3
      #Task.new(@screen, @game, :wait => 1000) {@max_speed = MAX_SPEED
      #  @acceleration = 0.1}
    when :invincibility
      @invincible = true
      @color.alpha = 70
      Task.new(@screen, @game, :wait => 1000) do
        @invincible = false
        @color.alpha = 255
      end
    when :slow
      @max_speed = MAX_SPEED - 4
      @acceleration = 0.07
      Task.new(@screen, @game, :wait => 1000) do
        @max_speed = MAX_SPEED
        @acceleration = 0.1
      end
    when :turn
      @turn_speed = 6
      Task.new(@screen, @game, :wait => 1000) { @turn_speed = 3 }
    when :turn_slow
      @turn_speed = 1.5
      Task.new(@screen, @game, :wait => 1000) { @turn_speed = 3 }
=end
    when :super_shot
      @charge = 1000
    when :life
      @lives += 1
    when :score
      add_score(5)
    end
  end

  def normalize
    @powerup_counters = {}
    @max_speed = MAX_SPEED
    @acceleration = 0.15
    @turn_speed = 3
    @invincible = false
    @protected = false
    @color.alpha = 255
    @charge = 20
    @life_span = 0
    @is_dead = false unless @lives == 0
  end

  def level_end
    @protected = true
    @life_span = 0 # for protected drawing calculations
  end

  def invincible?
    return (@invincible or @protected)
  end

  def add_score(score = 1)
    @score += score
    @lives += 1 if @screen.mode == :co_op and @score %50 < score
  end

end
